﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using deckAnalyser.Support;
using System.IO;

namespace deckAnalyser.Domain
{
  public class Deck : DomainObject
  {
    private String name;
    public String Name
    {
      get { return name; }
      set { name = value; IsDirty = true; NotifyListeners(); }
    }

    private String author;
    public String Author
    {
      get { return author; }
      set { author = value; IsDirty = true; NotifyListeners(); }
    }

    private String notes;
    public String Notes
    {
      get { return notes; }
      set { notes = value; IsDirty = true; NotifyListeners(); }
    }

    private string fileName = "";
    public string FileName
    {
      get { return fileName; }
      set { fileName = value; NotifyListeners(); }
    }

    public Deck(String name, String author, String notes)
    {
      this.name = name;
      this.author = author;
      this.notes = notes;
      IsDirty = true;
    }

    public Deck(String fileName)
    {
      this.fileName = fileName;
      loadFromFile(fileName);
      IsDirty = false;
    }

    public Deck(byte[] data)
    {
      this.fileName = null;
      loadFromByteArray(data);
      IsDirty = true;
    }

    public void Save()
    {
      TextWriter tw = new StreamWriter(fileName);

      tw.WriteLine("// {0}, by {1}", name, author);
      tw.WriteLine("// {0}", notes);

      foreach (Card card in mainDeck.Keys)
        tw.WriteLine("  {0} {1}", mainDeck[card], card.Name);

      tw.WriteLine();
      tw.WriteLine("// Sideboard:");

      foreach (Card card in sideboard.Keys)
        tw.WriteLine("SB: {0} {1}", sideboard[card], card.Name);

      tw.WriteLine();

      tw.Close();

      IsDirty = false;
      NotifyListeners();
    }


    private void loadFromByteArray(byte[] data)
    {
      MemoryStream ms = new MemoryStream(data);
      StreamReader sr = new StreamReader(ms);

      //String text = sr.ReadToEnd();

      List<String> lines = new List<string>();
      String dataLine = "";
      while (dataLine != null)
      {
        dataLine = sr.ReadLine();
        if (dataLine != null)
          lines.Add(dataLine.Trim());
      }
      sr.Close();

      load(lines);


    }


    private void loadFromFile(String fileName)
    {
      TextReader tr = new StreamReader(fileName);
      List<String> lines = new List<string>();
      String dataLine = "";
      while (dataLine != null)
      {
        dataLine = tr.ReadLine();
        if (dataLine != null)
          lines.Add(dataLine.Trim());
      }
      tr.Close();

      load(lines);
    }


    private Dictionary<Card, int> mainDeck = new Dictionary<Card, int>();
    private Dictionary<Card, int> sideboard = new Dictionary<Card, int>();
    private void load(List<String> lines)
    {
      // Clear the main variables
      mainDeck.Clear();
      sideboard.Clear();

      // Parse the file
      //
      int lineNo = 0;
      foreach (String line in lines)
      {
        if (String.IsNullOrEmpty(line))
        {
        }
        else if (line.StartsWith("//"))
        {
          if (lineNo == 0)
          {
            String[] tokens = line.Split(',');

            if (tokens.Length >= 2)
            {
              name = tokens[0].Replace("//", "").Trim();
              author = tokens[1].Replace("by", "").Trim();
            }
            else if (tokens.Length == 1)
            {
              name = tokens[0].Trim();
              author = "Unknown";
            }
            else
            {
              name = "Unknown";
              author = "Unknown";
            }
          }
          else if (lineNo == 1)
          {
            notes = line.Replace("//", "").Trim();
          }
        }
        else
        {

          bool sb = false;
          String[] tokens;
          if (line.StartsWith("SB:"))
          {
            tokens = line.Replace("SB:", "").Split(new String[] { " " }, StringSplitOptions.RemoveEmptyEntries);
            sb = true;
          }
          else
          {
            tokens = line.Split(new String[] { " " }, StringSplitOptions.RemoveEmptyEntries); ;
          }

          if (tokens.Length < 2)
            throw new Exception("Invalid file format.");

          int count = int.Parse(tokens[0].Trim());
          String name = String.Join(" ", tokens, 1, tokens.Length - 1);

          if (sb)
            sideboard.Add(new Card(name), count);
          else
            mainDeck.Add(new Card(name), count);
        }

        lineNo++;
      }
    }

    public int[] GetManaHistogram(bool forMainDeck)
    {
      int[] retVal = new int[10];

      Dictionary<Card, int> source = forMainDeck ? mainDeck : sideboard;

      foreach (Card card in source.Keys)
      {
        if (!card.IsLand)
          retVal[card.CMC] += source[card];
      }

      return retVal;
    }

    public Dictionary<String, int[]> GetManaComposition(bool forMainDeck)
    {
      Dictionary<Card, int> source = forMainDeck ? mainDeck : sideboard;
      
      Dictionary<String, int[]> retVal = new Dictionary<string, int[]>();

      foreach (Card card in source.Keys)
      {
        foreach (String type in card.Types)
        {
          if (!retVal.Keys.Contains(type))
            retVal[type] = new int[] { 0, 0, 0, 0, 0, 0 };

          if (card.IsWhite) retVal[type][0] += source[card];
          if (card.IsBlue) retVal[type][1] += source[card];
          if (card.IsBlack) retVal[type][2] += source[card];
          if (card.IsRed) retVal[type][3] += source[card];
          if (card.IsGreen) retVal[type][4] += source[card];
          if (card.IsArtifact) retVal[type][5] += source[card];
        }
      }

      return retVal;
    }

    public Dictionary<String, List<Card>> ToTypeDictionary(bool forMainDeck)
    {
      Dictionary<Card, int> source = forMainDeck ? mainDeck : sideboard;

      Dictionary<String, List<Card>> retVal = new Dictionary<string, List<Card>>();

      foreach (Card card in source.Keys)
      {
        if (!retVal.ContainsKey(card.Types[0]))
          retVal[card.Types[0]] = new List<Card>();

        retVal[card.Types[0]].Add(card);
      }

      return retVal;
    }


    public DataTable ToDataTable(bool forMainDeck)
    {
      Dictionary<String, List<Card>> list = ToTypeDictionary(forMainDeck);

      DataTable retVal = new DataTable("Deck");
      retVal.Columns.Add("Need", typeof(int));

      DataColumn pk = retVal.Columns.Add("Card Name", typeof(String));
      retVal.PrimaryKey = new DataColumn[] { pk };
      retVal.Columns.Add("Count", typeof(int));
      retVal.Columns.Add("Object", typeof(object));

      foreach (String key in list.Keys)
      {
        DataRow newRow1 = retVal.NewRow();

        newRow1["Card Name"] = key;
        newRow1["Need"] = DBNull.Value;
        newRow1["Count"] = DBNull.Value;
        newRow1["Object"] = null;

        retVal.Rows.Add(newRow1);

        int count = 0;
        foreach (Card card in list[key])
        {
          int haveCount = 0;
          String haveCountStr = DBWrapper.ExecuteScalar(
            " SELECT ifnull(sum(c.cnt)+sum(c.fcnt),0)" +
            " FROM   collections.collectioncards c" +
            " WHERE  c.name = '" + Options.Get("DefaultCollection", "Default") + "'" +
            " AND    c.cardname = '" + card.Name.Replace("'","''") + "'"
          );

          if (haveCountStr != null)
            haveCount = int.Parse(haveCountStr);


          DataRow newRow = retVal.NewRow();

          int needCount = forMainDeck?mainDeck[card]:sideboard[card];

          newRow["Card Name"] = card.Name;
          newRow["Need"] = (haveCount >= needCount) ? 0 : (needCount - haveCount);
          newRow["Count"] = needCount;
          newRow["Object"] = card;

          count += forMainDeck?mainDeck[card]:sideboard[card];

          retVal.Rows.Add(newRow);
        }

        newRow1["Card Name"] = "[-] " + key;
        newRow1["Count"] = count.ToString();
      }

      return retVal;
    }

    public override string Caption
    {
      get
      {
        if (IsDirty)
          return "* " + Name;
        else
          return Name;
      }
    }

    public void AddCard(String name)
    {
      Card c = (from x in mainDeck.Keys where x.Name == name select x).FirstOrDefault<Card>();

      if (c == null)
        mainDeck.Add(new Card(name), 1);
      else
        mainDeck[c]++;

      IsDirty = true;
      NotifyListeners();
    }

    public void RemoveCard(String name)
    {
      Card c = (from x in mainDeck.Keys where x.Name == name select x).FirstOrDefault<Card>();

      if (c != null)
        if (--mainDeck[c] == 0)
          mainDeck.Remove(c);

      IsDirty = true;
      NotifyListeners();
    }

  }
}
